package com.yss.sofa.report.engine.poi;

import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.io.FileInputStream;
import java.text.AttributedString;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;

import com.yss.sofa.report.engine.Activator;

public class SheetUtil2 {
    private static final char defaultChar = '0';
    private static final List<String> FONT_NAMES=Arrays.asList(java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
    private static final Properties EXCEL_FONT_ZISE=new Properties();
    private static final double fontHeightMultiple = 2.0;
    private static final FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
    
    private static double getCellWidth(Cell cell, float defaultCharWidth, DataFormatter formatter, boolean useMergedCells, FormulaEvaluator evaluator) {
        Sheet sheet = cell.getSheet();
        Workbook wb = sheet.getWorkbook();
        Row row = cell.getRow();
        int column = cell.getColumnIndex();
        int colspan = 1;
        for (int i = 0 ; i < sheet.getNumMergedRegions(); i++) {
            CellRangeAddress region = sheet.getMergedRegion(i);
            if (containsCell(region, row.getRowNum(), column)) {
                if (!useMergedCells) {
                    return -1;
                }
                cell = row.getCell(region.getFirstColumn());
                colspan = 1 + region.getLastColumn() - region.getFirstColumn();
            }
        }
        CellStyle style = cell.getCellStyle();
        Font font = wb.getFontAt(style.getFontIndex());
        double width = -1;
        String display = formatter.formatCellValue(cell, evaluator);
        String[] lines = display.split("\\n");
        for (int i = 0; i < lines.length; i++) {
            String txt = lines[i] + defaultChar;

            AttributedString str = new AttributedString(txt);
            copyAttributes(font, str, 0, txt.length());
            width = getCellWidth(defaultCharWidth, colspan, style, width, str);
        }
        return width;
    }

    private static double getCellWidth(float defaultCharWidth, int colspan,
            CellStyle style, double width, AttributedString str) {
        TextLayout layout = new TextLayout(str.getIterator(), fontRenderContext);
        if(style.getRotation() != 0){
            AffineTransform trans = new AffineTransform();
            trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
            trans.concatenate(
            AffineTransform.getScaleInstance(1, fontHeightMultiple)
            );
            width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth()*96/72 / colspan) / defaultCharWidth) + style.getIndention());
        } else {
            width = Math.max(width, ((layout.getBounds().getWidth()*96/72 / colspan) / defaultCharWidth) + style.getIndention());
        }
        return width;
    }

    private static double getColumnWidth(float defaultCharWidth, Sheet sheet, int column, boolean useMergedCells, int firstRow, int lastRow, FormulaEvaluator evaluator){
        DataFormatter formatter = new DataFormatter();
        double width = -1;
        for (int rowIdx = firstRow; rowIdx <= lastRow; ++rowIdx) {
            Row row = sheet.getRow(rowIdx);
            if( row != null ) {
                Cell cell = row.getCell(column);
                if (cell == null) {
                    continue;
                }
                double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells, evaluator);
                width = Math.max(width, cellWidth);
            }
        }
        return width;
    }

    private static void copyAttributes(Font font, AttributedString str, int startIdx, int endIdx) {
    	//if(!FONT_NAMES.contains(font.getFontName())){
    	//	System.err.println("font:["+font.getFontName()+"] is not exist.");
    	//}
        str.addAttribute(TextAttribute.FAMILY, font.getFontName(), startIdx, endIdx);
        str.addAttribute(TextAttribute.SIZE, (float)font.getFontHeightInPoints());
        if (font.getBold()) str.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIdx, endIdx);
        if (font.getItalic() ) str.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIdx, endIdx);
        if (font.getUnderline() == Font.U_SINGLE ) str.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIdx, endIdx);
    }

    private static boolean containsCell(CellRangeAddress cr, int rowIx, int colIx) {
        if (cr.getFirstRow() <= rowIx && cr.getLastRow() >= rowIx
                && cr.getFirstColumn() <= colIx && cr.getLastColumn() >= colIx)
        {
            return true;
        }
        return false;
    }
    
    public static double getColumnWidth(float defaultCharWidth,Sheet sheet, int column, boolean useMergedCells, FormulaEvaluator evaluator) {
        return getColumnWidth(defaultCharWidth,sheet, column, useMergedCells, sheet.getFirstRowNum(), sheet.getLastRowNum(), evaluator);
    }
    private static float getExcelCharWidth(Font font) throws Exception{
    	//load properties
    	if(EXCEL_FONT_ZISE.isEmpty()){
    		EXCEL_FONT_ZISE.load(new FileInputStream(Activator.FONT_PATH+"excel-font-size.properties"));
    	}
    	float result=8.0f;
		String width=EXCEL_FONT_ZISE.getProperty(font.getFontName()+"."+font.getFontHeightInPoints());
		if(StringUtils.isNumeric(width)){
			result=Float.valueOf(width);
		} else if(FONT_NAMES.contains(font.getFontName())){
			AttributedString str = new AttributedString(String.valueOf(defaultChar));
	        copyAttributes(font, str, 0, 1);
	        TextLayout layout = new TextLayout(str.getIterator(), fontRenderContext);
	        result = layout.getAdvance()*96/72;
		} else {
			width=EXCEL_FONT_ZISE.getProperty("宋体"+"."+font.getFontHeightInPoints());
			if(StringUtils.isNumeric(width)){
				result=Float.valueOf(width);
			}
		}
    	return result;
    }
    public static float getDefaultCharWidth(Workbook excel) throws Exception{
    	Font defaultFont = excel.getFontAt((short) 0);
		return getExcelCharWidth(defaultFont);
    }
}
